from PyQt6 import QtCore
from PyQt6.QtGui import QStandardItem

from .QAsyncSsdevClient import QAsyncSsdevClient

NodeTypeDir = 1
NodeTypeService = 2
NodeTypeMethod = 3


class SsdevRpcNode(object):
    def __init__(self, parent: 'SsdevRpcNode', path: str,
                 node_type: int = NodeTypeDir, name: str = '', children=[]):
        self._parent = parent
        self.path = path if not path.endswith("/") else path[:-1]
        self.name = name if len(name) > 0 else path.split("/")[-1]
        self._children = children
        self.node_type = node_type
        self._column_count = 1
        self._row = 0
        self.parameters = {}
        self.standard_item = QStandardItem(self.name)
        self.standard_item.setData(self, QtCore.Qt.ItemDataRole.UserRole)

    def _get_children(self):
        if self.is_service:
            return []
        else:
            return self._children

    def is_service(self):
        return self.node_type == NodeTypeService

    def column_count(self):
        return self._column_count

    def child_count(self):
        children = self._get_children()
        return len(children)

    def child(self, row):
        children = self._get_children()
        if 0 <= row < len(children):
            child = children[row]
            return child

    def parent(self):
        return self._parent

    def row(self):
        return self._row

    def data(self, column):
        return self.name

    def add_child(self, path: str):
        path = self.path+'/'+path

        child = SsdevRpcNode(self, path)

        if '.' in child.name:
            child.node_type = NodeTypeService

        self._children.append(child)
        self.standard_item.appendRow(child.standard_item)
        return child

    def add_service_desc(self, service_desc):
        methods = service_desc['methods']
        for m in methods:
            method_node = SsdevRpcNode(self, self.name, NodeTypeMethod, m['name'])
            method_node.parameters = m['parameters']
            self.standard_item.appendRow(method_node.standard_item)


class QAsyncSsdevRpcResolver(QtCore.QObject):
    def __init__(self, client: QAsyncSsdevClient,
                 utils_service_id='pay-balance-service.rpcUtilsService',
                 parent=None):
        super(QAsyncSsdevRpcResolver, self).__init__(parent)
        self.client = client
        self.utils_service_id = utils_service_id
        self.zk_root = '/ssdev/services'

        self.method_get_children = 'getChildren'
        self.method_get_service_desc = 'getServiceDesc'

    async def _get_children(self, root: str = None):
        path = root if root is not None else self.zk_root

        children = await self.client.invoke_rpc(self.utils_service_id, self.method_get_children, path)
        return children

    async def _get_service_desc(self, path: str):
        desc = await self.client.invoke_rpc(self.utils_service_id, self.method_get_service_desc, path)
        return desc

    def _root(self):
        root = SsdevRpcNode(None, self.zk_root, '/')
        return root

    async def walk_tree(self, node: SsdevRpcNode = None):
        node = node if node is not None else self._root()
        zk_children = await self._get_children(node.path)

        children = [node.add_child(child) for child in zk_children]

        if children is not None and len(children) > 0:
            dir_children = [child for child in children if child.node_type == NodeTypeDir]
            service_children = [child for child in children if child.node_type == NodeTypeService]
            for child in dir_children:
                await self.walk_tree(child)

            for child in service_children:
                path = child.path
                desc = await self._get_service_desc(path)
                child.add_service_desc(desc)

        return node

